import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Random;


class PeerKeyPair
{
    PublicKey pubKey;
    PrivateKey privKey;
    
    public PeerKeyPair(PublicKey pub, PrivateKey priv) 
    {
        this.pubKey = pub;
        this.privKey = priv;
    }
}

class DataSignature
{
    byte[] data;
    byte[] signature;
    public DataSignature(byte[] data, byte[] signature) 
    {
        this.data = data;
        this.signature = signature;
    }
}

public class Utilities 
{
    public static PeerKeyPair generateMyKeys()
    {
        PeerKeyPair peerKeys = null;
        try 
        {
                SecureRandom random = SecureRandom.getInstance(Constants.randomAlgo, Constants.provider);
                KeyPairGenerator keyGen = KeyPairGenerator.getInstance(Constants.keyAlgo);
                
                byte[] userSeed = new byte[Constants.SEED_SIZE];
                new Random().nextBytes(userSeed);
                random.setSeed(userSeed);
                
                keyGen.initialize(Constants.KEY_SIZE, random);
                KeyPair pair = keyGen.generateKeyPair();
                peerKeys = new PeerKeyPair(pair.getPublic(), pair.getPrivate());
        } 
        catch (NoSuchAlgorithmException e) 
        {
                // TODO Auto-generated catch block
				System.out.println("ERROR in key generation - "+e.getMessage());
        }
        catch (NoSuchProviderException e) 
        {
                // TODO Auto-generated catch block
				System.out.println("ERROR in key generation - "+e.getMessage());
        }
        return peerKeys;
    }

        
    public static byte[] signMyData(byte[] data,PrivateKey priv)
    {
        Signature dsa;
        byte[] signature = null;

        try 
        {
                dsa = Signature.getInstance(Constants.signAlgo);
                dsa.initSign(priv);
                dsa.update(data);
                signature = dsa.sign();

        } 
        catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
				System.out.println("ERROR in signing data - "+e.getMessage());
        }
        
        catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
				System.out.println("ERROR in signing data - "+e.getMessage());
        }
        catch (SignatureException e) {
                // TODO Auto-generated catch block
				System.out.println("ERROR in signing data - "+e.getMessage());
        }
        return signature;
    }
        
    public static boolean verifySignedData(Payload payload,PublicKey pub)
    {
        Signature dsa;
        boolean verified = false;
        try 
        {
                dsa = Signature.getInstance(Constants.signAlgo);
                dsa.initVerify(pub);
                dsa.update(payload.payloadByteArray());
                verified = dsa.verify(payload.payloadSignature);
        } 
        catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
				System.out.println("ERROR in verifying data - "+e.getMessage());
        }
        
        catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
				System.out.println("ERROR in verifying data - "+e.getMessage());
        }
        catch (SignatureException e) {
                // TODO Auto-generated catch block
				System.out.println("ERROR in verifying data - "+e.getMessage());
        }
        return verified;
    }
    
    public static boolean verifyHash(byte[] dataToVerify, String dataHash)
    {
        MessageDigest m =  null;
		try 
		{
			m = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        m.update(dataToVerify);
        String resultantHash = new String(m.digest());
        if (resultantHash.length() == 31) 
        {
        	resultantHash = "0" + resultantHash;
    	}
        if (resultantHash.equals(dataHash))
        {
        	return true;
        }
        return false;
    }

    public static String hashMyData(byte[] data)
    {
        MessageDigest m =  null;
		try 
		{
			m = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        m.update(data);
        String dataHash = new String(m.digest());
        if (dataHash.length() == 31) 
        {
        	dataHash = "0" + dataHash;
    	}
        return dataHash;

    }

    
}

